package com.yinxianren.main.study.netty.one;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.concurrent.GlobalEventExecutor;

public class SimpleChatServer {
    private int port;        // 端口

    public SimpleChatServer(int port) {
        this.port = port;
    }

    // 配置并开启服务器
    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();        // 用来接收进来的连接
        EventLoopGroup workerGroup = new NioEventLoopGroup();    // 用来处理已接收的连接

        try {
            ServerBootstrap sb = new ServerBootstrap();            // 启动NIO服务的辅助启动类
            sb.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)                // 设置如何接受连接
                    .childHandler(new SimpleChatServerInitializer())    // 配置Channel
                    .option(ChannelOption.SO_BACKLOG, 128)                // 设置缓冲区
                    .childOption(ChannelOption.SO_KEEPALIVE, true);    // 启用心跳机制

            System.out.println("SimpleChatServer 启动了");
            ChannelFuture future = sb.bind(port).sync();        // 绑定端口，开始接收连接
            future.channel().closeFuture().sync();                // 等待关闭服务器（不会发生）
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
            System.out.println("SimpleChatServer 关闭了");
        }
    }

    public static void main(String[] args) throws Exception {
        int port = 8080;
        new SimpleChatServer(port).run();     // 开启服务器
    }
}
/**
 * 服务端处理器
 */
class SimpleChatServerHandler extends SimpleChannelInboundHandler<String> {

    public static ChannelGroup channels
            = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    /**
     * 收到新的客户端连接时调用
     * 将客户端channel存入列表，并广播消息
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel incoming = ctx.channel();
        // 广播加入消息
        channels.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 加入\n");
        channels.add(incoming);        // 存入列表
    }

    /**
     * 客户端连接断开时调用
     * 广播消息
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel incoming = ctx.channel();
        // 广播离开消息
        channels.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 离开\n");
        // channel会自动从ChannelGroup中删除
    }

    /**
     * 收到消息时调用
     * 将消息转发给其他客户端
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        Channel incoming = ctx.channel();
        for(Channel channel : channels) {        // 遍历所有连接的客户端
            if(channel != incoming) {            // 其他客户端
                channel.writeAndFlush("[" + incoming.remoteAddress() + "] " + msg + "\n" );
            } else {                            // 自己
                channel.writeAndFlush("[you] " + msg + "\n" );
            }
        }
    }

    /**
     * 监听到客户端活动时调用
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Channel incoming = ctx.channel();
        System.out.println("SimpleChatClient: " + incoming.remoteAddress() + " 在线");
    }

    /**
     * 监听到客户端不活动时调用
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel incoming = ctx.channel();
        System.out.println("SimpleChatClient: " + incoming.remoteAddress() + " 掉线");
    }

    /**
     * 当Netty由于IO错误或者处理器在处理事件抛出异常时调用
     * 关闭连接
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        Channel incoming = ctx.channel();
        System.out.println("SimpleChatClient: " + incoming.remoteAddress() + " 异常");
    }
}

/**
 * 服务器配置初始化
 * 添加多个处理器
 */
class SimpleChatServerInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        // 添加处理类
        // 使用'\r''\n'分割帧
        pipeline.addLast("framer",
                new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
        // 解码、编码器
        pipeline.addLast("decoder", new StringDecoder());
        pipeline.addLast("encoder", new StringEncoder());
        // 处理器
        pipeline.addLast("handler", new SimpleChatServerHandler());

        System.out.println("SimpleChatClient: " + ch.remoteAddress() + "连接上");
    }

}